package com.lzw.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PostMapping;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author liuzw
 * @date 2021/8/17
 */
@Slf4j
@Component
public class Utils {

    public static final String MSG_TP_REGEXP_DCEP = "dcep.%s.001.01";

    /**
     * 机器IP 例如127.0.0.1
     */
    private static String hostName;
    /**
     * 机器IP去. 例如127001
     */
    private static String hostIp;

    public Utils() {
        try {
            hostName = InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            log.error("ip加载异常", e);
        }
        hostIp = hostName.replaceAll("\\.", "");
        log.info("加载HOSTNAME[{}]", hostName);
    }

    public static String getHostName() {
        return hostName;
    }

    public static String getHostIp() {
        return hostIp;
    }

    public static String getHostNameWithoutSpot() {
        return getHostIp();
    }

    /**
     * 通过批次号获取日期
     *
     * @param batchId 批次号
     * @return 日期
     */
    public static String getTradeDate(@NonNull String batchId) {
        //根据批次号，获取交易日期
        Assert.notNull(batchId, "批次号不允许为空");
        Assert.isTrue(batchId.startsWith("B"), "批次号格式不正确,首字母错误");
        Assert.isTrue(batchId.length() == 13, "批次号格式不正确，长度错误");
        return batchId.substring(1, 9);
    }

    /**
     * 递归获取参数集合
     *
     * @param map     map
     * @param request request
     * @return request
     */
    public static String requestToMap(Map<String, String> map, String request) {
        int keyLength = request.indexOf('=');
        String key = request.substring(0, keyLength);
        int entryLength = request.indexOf('&');
        if (entryLength == -1) {
            String value = request.substring(keyLength + 1);
            map.put(key, value);
            return null;
        }
        String value = request.substring(keyLength + 1, entryLength);
        map.put(key, value);
        return requestToMap(map, request.substring(entryLength + 1));
    }

    public static List<String> getUrlKeys(Class<?> clazz, Class<?> methodClass) {
        PostMapping clazzPostMapping = clazz.getAnnotation(PostMapping.class);
        Method method;
        try {
            method = clazz.getMethod("execution", methodClass);
        } catch (NoSuchMethodException e) {
            return null;
        }
        List<String> listKeys = new ArrayList<>();
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        if (postMapping == null) {
            return listKeys;
        }
        if (clazzPostMapping == null) {
            List<String> keys = getUrlKeys(postMapping.value(), null);
            if (keys != null) {
                listKeys.addAll(keys);
            }
        } else {
            for (String str : clazzPostMapping.value()) {
                List<String> keys = getUrlKeys(postMapping.value(), str);
                if (keys != null) {
                    listKeys.addAll(keys);
                }
            }
        }
        return listKeys;
    }

    public static List<String> getUrlKeys(String[] arrays, String url) {
        if (ArrayUtils.isEmpty(arrays)) {
            return null;
        }
        if (url == null) {
            url = "";
        }
        List<String> list = Arrays.asList(arrays);
        final String finalUrl = url;
        return list.stream().map(array -> finalUrl + array).collect(Collectors.toList());
    }

    /**
     * 递归获取泛型类型
     *
     * @param clazz getClass
     * @return Type[]
     */
    public static Type[] getType(Class<?> clazz, Class<?> superClass) {
        Assert.isTrue(superClass.isAssignableFrom(clazz), String.format("%s is not %s super class", superClass, clazz));
        if (clazz.getSuperclass().isAssignableFrom(superClass)) {
            return ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments();
        } else {
            return getType(clazz.getSuperclass(), superClass);
        }
    }

    /**
     * 获取对象中为空的字段类型
     *
     * @param source Object
     * @return String[]
     */
    public static String[] getNullPropertyNames(Object source) {
        if (source == null) {
            return null;
        } else {
            BeanWrapper src = new BeanWrapperImpl(source);
            PropertyDescriptor[] pds = src.getPropertyDescriptors();
            Set<String> emptySet = new HashSet<>();

            for (PropertyDescriptor pd : pds) {
                Object value = src.getPropertyValue(pd.getName());
                if (value == null) {
                    emptySet.add(pd.getName());
                }
            }

            List<String> list = new ArrayList<>(emptySet);
            String[] str = new String[list.size()];
            return list.toArray(str);
        }
    }

    /**
     * Object转JSON
     * 字符串不处理
     *
     * @param obj Object
     * @return String
     */
    public static String objectToJson(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj instanceof String) {
            return (String) obj;
        }
        return JsonUtils.toJson(obj);
    }

    public static String yuanToFen(String yuan) {
        if (StringUtils.isBlank(yuan)) {
            return yuan;
        }
        return new BigDecimal(yuan).multiply(new BigDecimal("100")).stripTrailingZeros().toPlainString();
    }

    public static String fenToYuan(String yuan) {
        if (StringUtils.isBlank(yuan)) {
            return yuan;
        }
        return new BigDecimal(yuan).multiply(new BigDecimal("0.01")).setScale(2, BigDecimal.ROUND_UNNECESSARY).toPlainString();
    }
}
